﻿using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework.Content;
using System;

namespace ShevaEngine.Core.Modules.Models
{
    /// <summary>
    /// Represents a keyframe in an animation track.
    /// </summary>
    [ContentSerializerRuntimeTypeAttribute("ShevaEngine.Core.Modules.Models.BoneKeyframe, ShevaEngine2")]
    public class BoneKeyframe
    {
        /// <summary>The transform for the keyframe.</summary>
        public Matrix Transform { get; set; }
        /// <summary>The time for the keyframe.</summary>
        public long Time { get; set; }

        /// <summary>
        /// Konstruktor pro content pipeline.
        /// </summary>
        public BoneKeyframe()
        {

        }

        /// <summary>
        /// Creats a new BoneKeyframe.
        /// </summary>
        /// <param name="time">The time in ticks for the keyframe.</param>
        /// <param name="transform">The transform for the keyframe.</param>        
        public BoneKeyframe(Matrix transform, long time)
        {
            this.Transform = transform;
            this.Time = time;
        }

    }

    /// <summary>
    /// A collection of BoneKeyFrames that represents an animation track.
    /// </summary>
    [ContentSerializerRuntimeTypeAttribute("ShevaEngine.Core.Modules.Models.BoneKeyframeCollection, ShevaEngine2")]
    public class BoneKeyframeCollection : List<BoneKeyframe>
    {
        /// <summary>Gets the duration of the animation track.</summary>
        public long Duration { get; private set; }

        /// <summary>
        /// Konstruktor.
        /// </summary>
        public BoneKeyframeCollection()
            : base()
        {

        }

        // Only allow creation from inside the library (only in AnimationReader)
        public BoneKeyframeCollection(string boneName,
            IList<BoneKeyframe> list)
            : base(list)
        {
            this.Duration = list[list.Count - 1].Time;
        }

        /// <summary>
        /// Gets the index in the track at the given time.
        /// </summary>
        /// <param name="ticks">The time for which the index is found.</param>
        /// <returns>The index in the track at the given time.</returns>
        public int GetIndexByTime(long ticks)
        {
            // Since the animation is usually interpolated to 60 fps, this will
            // almost always be the index to return
            int firstFrameIndexToCheck = (int)(ticks / Util.TICKS_PER_60FPS);
            // Do out of bounds checking
            if (firstFrameIndexToCheck >= base.Count)
                firstFrameIndexToCheck = base.Count - 1;
            // Increment the index until the time at the next index is greater than the
            // specified time
            while (firstFrameIndexToCheck < base.Count - 1 && base[firstFrameIndexToCheck + 1].Time < ticks)
            {
                ++firstFrameIndexToCheck;
            }
            // Decrement the index till the time at the index is not greater than the
            // specified time
            while (firstFrameIndexToCheck >= 0 && base[firstFrameIndexToCheck].Time >
                ticks)
            {
                --firstFrameIndexToCheck;
            }

            return firstFrameIndexToCheck;
        }
    }
}
